package ru.osu.acm.common.industrial;

import ru.osu.acm.common.entities.Problem;
import ru.osu.acm.common.entities.Checker;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * User: aleksey
 * Date: Sep 22, 2009
 * Time: 10:18:37 AM
 */
public class ProblemFactory extends Factory {
    public static Problem getProblem(int problemId, Connection con, boolean closeConnection) {
        Problem problem = null;

        try {
            PreparedStatement statement = con.prepareStatement("select * from problem where id = ?");
            statement.setInt(1, problemId);
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                problem = new Problem(
                        resultSet.getInt("id"),
                        resultSet.getString("problemname").trim(),
                        resultSet.getString("inputfile").trim(),
                        resultSet.getString("outputfile").trim(),
                        resultSet.getInt("timelimit"),
                        CheckerFactory.getChecker(resultSet.getInt("checker"), con, false),
                        resultSet.getString("statement").trim(),
                        resultSet.getString("input_description").trim(),
                        resultSet.getString("output_description").trim(),
                        resultSet.getString("input_example").trim(),
                        resultSet.getString("output_example").trim(),
                        -1);
            }
            resultSet.close();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
        return problem;
    }

    public static ArrayList<Problem> getAllProblems(Connection con, boolean closeConnection) {
        ArrayList<Problem> problems = new ArrayList<Problem>();

        try {
            PreparedStatement statement = con.prepareStatement("select * from problem order by id");
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                problems.add(new Problem(
                        resultSet.getInt("id"),
                        resultSet.getString("problemname").trim(),
                        resultSet.getString("inputfile").trim(),
                        resultSet.getString("outputfile").trim(),
                        resultSet.getInt("timelimit"),
                        CheckerFactory.getChecker(resultSet.getInt("checker"), con, false),
                        resultSet.getString("statement").trim(),
                        resultSet.getString("input_description").trim(),
                        resultSet.getString("output_description").trim(),
                        resultSet.getString("input_example").trim(),
                        resultSet.getString("output_example").trim(),
                        -1));
            }
            resultSet.close();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
        return problems;
    }

    public static ArrayList<Problem> getContestProblems(int contestId, Connection con, boolean closeConnection) {
        ArrayList<Problem> problems = new ArrayList<Problem>();

        try {
            PreparedStatement statement = con.prepareStatement("select * from contestproblem where contest = ? order by problemindex asc");
            statement.setInt(1, contestId);
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                Problem problem = getProblem(resultSet.getInt("problem"), con, false);
                problem.setIndex(resultSet.getInt("problemindex"));
                problems.add(problem);
            }
            resultSet.close();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
        return problems;
    }

    public static int getContestProblemCount(int contestId, Connection con, boolean closeConnection) {
        int count = 0;

        try {
            PreparedStatement statement = con.prepareStatement("select count(*) as problemcount from contestproblem where contest = ?");
            statement.setInt(1, contestId);
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                count = resultSet.getInt("problemcount");
            }
            resultSet.close();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
        return count;
    }

    public static void removeProblemFromContest(int problemId, int contestId, Connection con, boolean closeConnection) {
        int index = 0;

        try {
            PreparedStatement statement = con.prepareStatement("select problemindex from contestproblem where contest = ? and problem = ?");
            statement.setInt(1, contestId);
            statement.setInt(2, problemId);
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                index = resultSet.getInt("problemindex");
            }
            resultSet.close();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            PreparedStatement statement = con.prepareStatement("update contestproblem set problemindex = problemindex - 1 where contest = ? and problemindex > ?");
            statement.setInt(1, contestId);
            statement.setInt(2, index);
            statement.executeUpdate();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            PreparedStatement statement = con.prepareStatement("delete from contestproblem where problem = ? and contest = ?");
            statement.setInt(1, problemId);
            statement.setInt(2, contestId);
            statement.executeUpdate();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
    }

    public static void addProblemToContest(int problemId, int contestId, int index, Connection con, boolean closeConnection) {
        boolean alreadyAdded = false;

        try {
            PreparedStatement statement = con.prepareStatement("select * from contestproblem where contest = ? and problem = ?");
            statement.setInt(1, contestId);
            statement.setInt(2, problemId);
            ResultSet resultSet = statement.executeQuery();
            if (resultSet.next()) {
                alreadyAdded = true;
            }
            resultSet.close();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        if (alreadyAdded) {
            closeConnection(con, closeConnection);
            return;
        }

        try {
            int newId = getNextId("contestproblem", con, false);
            PreparedStatement statement = con.prepareStatement("insert into contestproblem(id, problem, contest, problemindex) values (?, ?, ?, ?)");
            statement.setInt(1, newId);
            statement.setInt(2, problemId);
            statement.setInt(3, contestId);
            statement.setInt(4, index);
            statement.executeUpdate();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
    }

    public static void updateProblem(Problem problem, Connection con, boolean closeConnection) {
        if (problem.getId() == -1) {
            problem.setId(getNextId("problem", con, false));

            try {
                PreparedStatement statement = con.prepareStatement("insert into problem (id, problemname, inputfile, " +
                        "outputfile, timelimit, checker, statement, input_description, output_description, " +
                        "input_example, output_example) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
                statement.setInt(1, problem.getId());
                statement.setString(2, problem.getName());
                statement.setString(3, problem.getInputFile());
                statement.setString(4, problem.getOutputFile());
                statement.setInt(5, problem.getTimeLimit(1));
                statement.setInt(6, problem.getChecker() == null ? Checker.DEFAULT_CHECKER : problem.getChecker().getId());
                statement.setString(7, problem.getStatement());
                statement.setString(8, problem.getInputDescription());
                statement.setString(9, problem.getOutputDescription());
                statement.setString(10, problem.getInputExample());
                statement.setString(11, problem.getOutputExample());
                statement.executeUpdate();
                statement.close();
            }
            catch (SQLException e) {
                e.printStackTrace();
            }

            closeConnection(con, closeConnection);
            return;
        }

        try {
            PreparedStatement statement = con.prepareStatement("update problem set problemname = ?, inputfile = ?, " +
                    "outputfile = ?, timelimit = ?, checker = ?, statement = ?, input_description = ?, " +
                    "output_description = ?, input_example = ?, output_example = ? where id = ?");
            statement.setString(1, problem.getName());
            statement.setString(2, problem.getInputFile());
            statement.setString(3, problem.getOutputFile());
            statement.setInt(4, problem.getTimeLimit(1));
            statement.setInt(5, problem.getChecker() == null ? Checker.DEFAULT_CHECKER : problem.getChecker().getId());
            statement.setString(6, problem.getStatement());
            statement.setString(7, problem.getInputDescription());
            statement.setString(8, problem.getOutputDescription());
            statement.setString(9, problem.getInputExample());
            statement.setString(10, problem.getOutputExample());
            statement.setInt(11, problem.getId());
            statement.executeUpdate();
            statement.close();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }

        closeConnection(con, closeConnection);
    }

    public static Problem getNewProblem(Connection con, boolean closeConnection) {
        return new Problem(-1, "", "file.in", "file.out", 2, CheckerFactory.getChecker(Checker.DEFAULT_CHECKER, con, closeConnection), "", "", "", "", "", -1);
    }
}
